
package com.esdk.sql.orm;

import cn.hutool.json.JSONUtil;
import cn.hutool.json.XML;
import com.alibaba.fastjson.JSONArray;
import com.esdk.esdk;
import com.esdk.interfaces.Adder;
import com.esdk.sql.*;
import com.esdk.utils.*;

import java.io.Closeable;
import java.io.Serializable;
import java.math.BigDecimal;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.function.*;
/***
 * @author 范飞宇
 * @since 2006.?.?
 */
public class ABResultSet<T extends IRow> implements Iterable<T>,IResultSetCursor,Closeable,IResultSet<T>,Serializable{
	protected transient ResultSet rs;
	protected List<T> rowList;
	protected transient ResultSetMetaData rsmd;
	protected int cursorPos=-1;
	private boolean isCachedAllRow=false;
	protected Map mapColumnClass;
	protected String[] columns;
	private boolean _isClosed;
	transient protected ISelect select;
	private transient int totalCount;
	private boolean allowNext=true;

	public ABResultSet(ResultSet resultset){
		rs=resultset;
		rowList=new ArrayList<>();
	}

	public ABResultSet(JSONArray ja){
		if(ja.size()>0)
			columns=ja.getJSONObject(0).keySet().toArray(new String[0]);
		rowList=new ArrayList();
		for(int i=0;i<ja.size();i++){
			new ABRow(ja.getJSONObject(i));
		}
	}

  public List<ABRowSet<T>> group(String... fields) {
  	return RowSetUtils.group(new ABRowSet(this),fields);
  }

	public List<ABRowSet<T>> group(Function<T,?> fn) {
		return RowSetUtils.group(new ABRowSet(this),fn);
	}

	public <R> Map<R,ABRowSet<T>> groupMap(Function<T,R> fn) {
		return RowSetUtils.groupMap(new ABRowSet(this),fn);
	}

	protected ResultSet resultSet(){
		return rs;
	}

	public void disConnect() throws SQLException{
		if(!rs.isClosed())
			last();
	}

	protected List<T> getSubList(int start,int limit) throws SQLException{
		int begin=start-1;
		if(cursorPos>begin)
			cursorPos=begin;
		else
			while(cursorPos<begin&&next()){}
		if(cursorPos==begin){
			for(int i=start,n=start+limit;i<n&&next();i++){}
			List<T> subRowList=rowList.subList(start,Math.min(start+limit,rowList.size()));
			close();
			return subRowList;
		}
		return rowList.subList(0,0);
	}

	@Override
	public <RS extends IResultSet> RS of(){
		ABResultSet<T> result=new ABResultSet<T>(rs);
		result.columns=this.columns;
		result.rsmd=this.rsmd;
		result.cursorPos=this.cursorPos;
		result._isClosed=this._isClosed;
		result.totalCount=this.totalCount;
		result.rowList=this.rowList;
		result.allowNext=this.allowNext;
		result.select=this.select;
		result.mapColumnClass=this.mapColumnClass;
		result.isCachedAllRow=this.isCachedAllRow;
		return (RS)result;
	}

	public ABRowSet<T> subRowSet(int start,int limit){
		try{
			List<T> subList=getSubList(start,limit);
			return subList==null?of():new ABRowSet(subList);
		}catch(SQLException e){
			throw new SQLRuntimeException(e);
		}
	}

	/**使用lambda表达式过滤*/
	public ABRowSet<T> filter(Predicate<T> fn){
		return filter(0,fn);
	}

	public ABRowSet<T> filter(int top,Predicate<T> fn){
		ABRowSet result=new ABRowSet(this.getColumns());
		if(top<=0)
			top=Integer.MAX_VALUE;
		for(T row:this) {
			if(fn.test(row)) {
				if(top-->0)
					result.add(row);
			}
		}
		return result;
	}

	public ABRowSet<T> filter(IRowFilter filter){
		this.size();
		return RowSetUtils.filter(new ABRowSet(this),filter);
	}

	@Override
	public ABRowSet<T> filter(IExpression exp){
		this.size();
		return RowSetUtils.filter(new ABRowSet(this),new RowFilter(exp));
	}

	@Override
	public ABRowSet<T> filter(int top,IExpression exp){
		this.size();
		return RowSetUtils.filter(new ABRowSet(this),new RowFilter(exp),top);
	}

	public ABRowSet<T> filter(String expr){
		return filter(0,expr);
	}

	public ABRowSet<T> filter(int top,String expr){
		try{
			this.size();
			ABRowSet<T> result=new ABRowSet(this,new EasyQuery(this.getAllRows()).filter(expr,top).toList());
			return result;
		}catch(Exception e){
			throw new SQLRuntimeException(e);
		}
	}

	/**使用lambda表达式过滤，只获取第1条件记录*/
	public T filterFirst(Predicate<T> fn){
		return filter(1,fn).getFirstRow();
	}

	/**使用lambda表达式过滤，只获取第1条件记录
	 * 参数autoCreateInstance:是否自动创建一个新实例
	 * */
	public T filterFirst(Predicate<T> fn,boolean autoCreateInstance){
		return filter(1,fn).getFirstRow(autoCreateInstance);
	}

	public T filterFirst(boolean autoCreateInstance,String fieldName,String expr,Object value){
		return filter(1,fieldName,expr,value).getFirstRow(autoCreateInstance);
	}

	public T filterFirst(String fieldName,Object value){
		return filter(1,fieldName,Exp.EQ,value).getFirstRow();
	}

	public T filterFirst(boolean autoCreateInstance,String fieldName,Object value){
		return filter(1,fieldName,Exp.EQ,value).getFirstRow(autoCreateInstance);
	}

	public ABRowSet<T> filter(String fieldName,Object equalValue){
		return filter(RowFilter.create(fieldName,equalValue));
	}

	public ABRowSet<T> filter(int top,String fieldName,Object equalValue){
		return filter(RowFilter.create(fieldName,equalValue).setTop(top));
	}

	/**可以一次输入多个and的条件，并支持所有的表达式。eg.: filter("name","张三",code,<>,test,"age","<",18)*/
	public ABRowSet<T> filters(String firstField,Object... args){
		args=esdk.array.concat(Object.class,firstField,args);
		RowExpressions expressions=new RowExpressions();
		String fieldValue=null,expression=Expression.EQ;
		Object rightValue=null;
		boolean isFieldValue=true;
		for(Object arg:args) {
			if(isFieldValue) {
				fieldValue=(String)arg;
				isFieldValue=false;
			}else if(esdk.array.contains(Expression.ALL,arg)) {
				expression=(String)arg;
			}else {
				rightValue=arg;
				isFieldValue=true;
				expressions.add(fieldValue,expression,rightValue);
				expression=Expression.EQ;
			}
		}
		return filter(expressions);
	}

	/**可以一次输入多个and的条件，并支持所有的表达式。eg.: filter("name","张三",code,<>,test,"age","<",18)*/
	public ABRowSet<T> filters(int top,String firstField,Object... args){
		args=esdk.array.concat(firstField,args);
		RowFilter result=null;
		String fieldValue=null,expression=Expression.EQ;
		Object rightValue=null;
		boolean isFieldValue=true;
		for(Object arg:args) {
			if(isFieldValue) {
				fieldValue=(String)arg;
				isFieldValue=false;
			}else if(esdk.array.contains(Expression.ALL,arg)) {
				expression=(String)arg;
			}else {
				rightValue=arg;
				isFieldValue=true;
				if(result==null)
					result=RowFilter.create(fieldValue,expression,rightValue).setTop(top);
				else
					result.add(fieldValue,expression,rightValue);
				expression=Expression.EQ;
			}
		}
		return filter(result);
	}

	public ABRowSet<T> filter(String fieldName,String expression,Object equalValue){
		return filter(RowFilter.create(fieldName,expression,equalValue));
	}

	public ABRowSet<T> filter(int top,String fieldName,String expression,Object equalValue){
		return filter(RowFilter.create(fieldName,expression,equalValue).setTop(top));
	}

	public List<Map> toMapList(){
		ArrayList result=new ArrayList(this.size());
		for(int i=0;i<rowList.size();i++){
			IRow row=(IRow)rowList.get(i);
			result.add(row.record());
		}
		return result;
	}

	public List<T> toRowList(){
		this.size();
		return (List<T>)rowList;
	}

	public List<Map> toMapList(boolean isFormatJavaBeanName){
		if(!isFormatJavaBeanName)
			return toMapList();
		ArrayList result=new ArrayList(this.size());
		for(int i=0;i<rowList.size();i++){
			IRow row=(IRow)rowList.get(i);
			result.add(esdk.map.toCamelCaseMap(row.record()));
		}
		return result;
	}

	public List<Map> toMapList(boolean isFormatJavaBeanName,String...columns){
		if(isFormatJavaBeanName){
			ArrayList result=new ArrayList(this.size());
			for(int i=0;i<rowList.size();i++){
				IRow row=(IRow)rowList.get(i);
				result.add(row.toMap(true,columns));
			}
			return result;
		}
		else{
			return toMapList();
		}
	}
	public List<Map> toMapList(boolean isFormatJavaBeanName,String[] columns,String[] excludeCols){
		ArrayList result=new ArrayList(this.size());
		for(int i=0;i<rowList.size();i++){
			IRow row=(IRow)rowList.get(i);
			if(esdk.array.isEmpty(excludeCols))
				result.add(row.toMap(isFormatJavaBeanName,columns));
			else
				result.add(row.toMap(isFormatJavaBeanName,columns,excludeCols));
		}
		return result;
	}
  /**默认输出驼峰格式，不输出扩展字段*/
	@Override
	public JSONArray toJsonArray(){
		return toJsonArray(true);
	}

	@Override
	public JSONArray toJsonArray(boolean isFormatJavaBeanName){
		return RowSetUtils.toJsonArray(this.toMapList(isFormatJavaBeanName),false);
	}

	@Override
  public JSONArray toJsonArray(boolean isFormatJavaBeanName,boolean isOutputExtraColumns){
		return RowSetUtils.toJsonArray(this.toMapList(isFormatJavaBeanName,isOutputExtraColumns?Constant.EmptyStrArr:columns),false);
  }

	@Override
	public JSONArray toJsonArray(boolean isFormatJavaBeanName,boolean isOutputExtraColumns,String[] columns,String[] excludeColumns){
		if(esdk.array.isEmpty(columns))
			columns=getColumns();
		return RowSetUtils.toJsonArray(this.toMapList(isFormatJavaBeanName,columns,excludeColumns),isFormatJavaBeanName);
	}

	@Override
  public JSONArray toJsonArray(boolean isFormatJavaBeanName,String... columns){
		return RowSetUtils.toJsonArray(this.toMapList(isFormatJavaBeanName,columns),false);
  }

	@Override
	public String toString(){
    StringBuilder result=new StringBuilder();
    int[] index=new int[]{0};
		for(int i=0,n=this.rowList.size();i<n;i++){
			IRow row=rowList.get(i);
			result.append((index[0]++)+"_"+row.getClass().getSimpleName()+row).append("\n");
			if(result.length()>10000){
				result.append("限制调试时输出，只显示前"+(i+1)+"条记录...\n");
				break;
			}
		}
    if(result.length()>0)
      result.delete(result.length()-1,result.length());
    return result.toString();
	}

	public JSONArray toJsonArray(int start,int limit){
		try{
			List<T> sub=this.getSubList(start,limit);
			JSONArray result=new JSONArray(sub.size());
			for(int i=0;i<sub.size();i++){
				result.add(sub.get(i).toJsonObject());
			}
			return result;
		}catch(SQLException e){
			throw new SQLRuntimeException(e);
		}
	}

	void addRowList(IRow currentRow) throws SQLException{
		rowList.add((T)currentRow);
	}

	public boolean next() throws SQLException{
		if(!allowNext)
			throw new SQLRuntimeException("使用了getNextRow()就不可以再使用next()!");
		if(rs!=null&&!isCachedAllRow&&rowList.size()==cursorPos+1){
			if(rs.next()){
				cursorPos++;
				if(cursorPos==rowList.size()){
					addRowList(getCurrent());
				}
			}else{
				isCachedAllRow=true;
				close();
				return false;
			}
		}else{
			if(cursorPos<rowList.size())
				cursorPos++;
		}
		return isRange();
	}

	/**
	 * 只读取数据，不保存，解决记录太多放到内存造成内存不足或内存泄露的问题，注意使用了这个方法，就不能再使用next()了
	 * 使用示例: for(IRow row=rs.getNextRow();row!=null;row=rs.getNextRow()){...}
	 * */
	public T getNextRow() throws SQLException{
		if(allowNext)
			allowNext=false;
		if(rs.next()){
			cursorPos++;
			return getCurrent();
		}else{
			close();
			return null;
		}
	}

	protected T getCurrent() throws SQLException{
		return (T)new ABRow(getCurrentMap());
	}

	public boolean first() throws SQLException{
		if(rowList.size()==0)
			next();
		if(rowList.size()>0){
			cursorPos=0;
		}
		return isRange();
	}

	public boolean last() throws SQLException{
		while(next()){
		}
		if(rowList.size()>0){
			cursorPos=rowList.size()-1;
			return true;
		}
		return false;
	}

	public int size(){
		return getRowSize();
	}

	private int getRowSize(){
		int mem=cursorPos;
		int result=0;
		try{
			if(last())
				result=rowList.size();
			cursorPos=mem;
			return result;
		}catch(SQLException e){
			esdk.error(e);
			cursorPos=mem;
			return result;
		}
	}

	public boolean previous(){
		if(cursorPos>=0)
			cursorPos--;
		return isRange();
	}

	private boolean isRange(){
		return isRange(cursorPos);
	}

	private boolean isRange(int row){
		return isRange(rowList,row);
	}

	static boolean isRange(List list,int row){
		return row>=0&&row<list.size();
	}

	protected void checkRange(int i){
		if(!isRange(i))
			throw new IndexOutOfBoundsException("index is"+i+" but size is "+rowList.size());
	}

	public boolean absolute(int position) throws SQLException{
		if(cursorPos>=position) {
			cursorPos=position;
			return true;
		}else {
			while(cursorPos < position && !isCachedAllRow) {
				next();
			}
		}
		if(isRange(position)){
			cursorPos=position;
			return true;
		}else
			return false;
	}

	public void beforeFirst(){
		cursorPos=-1;
	}

	public void afterLast() throws SQLException{
		if(last()){
			cursorPos++;
		}
	}

	public boolean isAfterLast() throws SQLException{
		return cursorPos>=rowList.size();
	}

	public boolean isBeforeFirst() throws SQLException{
		return cursorPos<0;
	}

	public int getCursor(){
		return cursorPos;
	}

	public Object gainCurrentRow() throws SQLException{
		return rowList.get(cursorPos);
	}

	public IRow getCurrentRow() throws SQLException{
		return (IRow)gainCurrentRow();
	}

	protected LinkedHashMap getCurrentMap() throws SQLException{
		rsmd=gainMetaData();
		LinkedHashMap result=new LinkedHashMap(rsmd.getColumnCount());
		for(int i=1,n=rsmd.getColumnCount();i<=n;i++){
			result.put(rsmd.getColumnLabel(i),RowUtils.getCurrentValue(rs,rsmd,i));
		}
		return result;
	}

	protected Object[] getCurrentArray() throws SQLException{
		rsmd=gainMetaData();
		Object[] result=new Object[rsmd.getColumnCount()];
		for(int i=1,n=rsmd.getColumnCount()+i;i<n;i++){
			result[i-1]=RowUtils.getCurrentValue(rs,rsmd,i);
		}
		return result;
	}

	public T getFirstRow(){
		return (T)getRow(0);
	}

	public T getFirstRow(boolean isCreateInstance){
		T result=(T)getRow(0);
		if(result==null&&isCreateInstance){
			result=(T)new ABRow(this.columns);
		}
		return result;
	}

	public T getLastRow(){
		return (T)getRow(this.size()-1);
	}

	public T getRow(){
		return (T)getRow(getCursor());
	}

	public IRow getRow(int index){
		try{
			for(int i=-1;index>cursorPos&&i<index&&next();i++){
				esdk.tool.nothing();
			}
			if(!isEmpty())
				return this.rowList.get(index);
			else
				return null;
		}catch(SQLException e){
			throw new SQLRuntimeException(e);
		}
	}

	protected ResultSetMetaData gainMetaData() throws SQLException{
		if(rsmd==null){
			rsmd=rs.getMetaData();
			mapColumnClass=getMapColumnClass();
		}
		return rsmd;
	}

	Map getMapColumnClass() throws SQLException{
		if(mapColumnClass==null){
			ResultSetMetaData rsmdata=gainMetaData();
			mapColumnClass=new LinkedHashMap(rsmdata.getColumnCount());
			for(int i=1,n=rsmdata.getColumnCount()+i;i<n;i++){
				mapColumnClass.put(rsmdata.getColumnLabel(i),esdk.reflect.loadClass(rsmdata.getColumnClassName(i)));
			}
		}
		return mapColumnClass;
	}

	protected boolean findAutoIncrement(String column) throws SQLException{
		ResultSetMetaData md=gainMetaData();
		for(int i=1,n=md.getColumnCount()+i;i<n;i++){
			if(md.getColumnLabel(i).equalsIgnoreCase(column))
				return md.isAutoIncrement(i);
		}
		throw new SQLException("can not find Column:"+column);
	}

	public String[] getColumns(){
		try{
			if(columns==null){
				gainMetaData();
				columns=new String[rsmd.getColumnCount()];
				/* gainMetaData(); */
				for(int i=0,n=rsmd.getColumnCount();i<n;i++){
					columns[i]=rsmd.getColumnLabel(i+1);
				}
			}
			return columns;
		}catch(Exception e){
			throw esdk.tool.wrapThrowble(e);
		}
	}

	protected List<T> gainAllRow() throws SQLException{
		int currentpos=cursorPos;
		columns=getColumns();
		last();
		cursorPos=currentpos;
		return rowList;
	}

	public boolean hasColumnName(String name){
		return EasyStr.existOf(columns,name);
	}

	public List<T> getAllRows() throws SQLException{
		return gainAllRow();
	}

	public void close(){
		try{
			if(_isClosed && (rs==null || rs.isClosed())){
				return;
			}
			else {
				getColumns();
				EasySql.close(rs);
				rs=null;
				_isClosed=true;
			}
		}catch(SQLException e){
			throw esdk.tool.wrapThrowble(e);
		}
	}

	public List<T> getRowList() throws SQLException{
		last();
		return (List)rowList;
	}

	public int findColumn(String columnLabel) throws SQLException{
		return rs.findColumn(columnLabel);
	}

	public boolean isEmpty() throws SQLException{
		int temp=getCursor();
		boolean res=!first();
		cursorPos=temp;
		return res;
	}

	public boolean isFirst() throws SQLException{
		return cursorPos==0;
	}

	public boolean isLast() throws SQLException{
		return cursorPos==rowList.size()-1;
	}

	public boolean relative(int offset) throws SQLException{
		if(offset==0)
			return isRange();
		if(isCachedAllRow){
			if(isRange(cursorPos+offset)){
				cursorPos+=offset;
				return true;
			}else
				return false;
		}else{
			if(offset>=0){
				for(int i=cursorPos;i<cursorPos+offset;i++){
					if(!next()){
						return false;
					}
				}
			}else{
				for(int i=cursorPos;i>cursorPos+offset;i--){
					if(!previous()){
						return false;
					}
				}
			}
		}
		return true;
	}

  public String toXml() {
  	ArrayList list=new ArrayList(rowList.size());
  	for(IRow row:rowList) {
  		list.add(row.toMap());
  	}
  	return XML.toXml(JSONUtil.parseArray(list),Constant.RowsetXmlIdentifier);
  }

  public String toXml(String[] labels) {
  	ArrayList list=new ArrayList(rowList.size());
  	for(IRow row:rowList) {
  		list.add(row.toMap(true,labels));
  	}
  	return XML.toXml(JSONUtil.parseArray(list),Constant.RowsetXmlIdentifier);
  }

	public String toCsv() throws SQLException{
		return toCsv(getColumns());
	}

	public String toCsv(boolean trim) throws SQLException{
		return toCsv(trim,getColumns());
	}

	public String toCsv(String...colums) throws SQLException{
		return toCsv(false,colums);
	}

	public String toCsv(boolean trim,String...colums) throws SQLException{
		return EasyStr.toCsv(toArray(trim,colums));
	}

	public List<List> toList(String...cols) throws SQLException{
		if(cols.length==0)
			cols=this.columns;
		List<List> result=new ArrayList<List>();
		List rowList=gainAllRow();
		for(Iterator iter=rowList.iterator();iter.hasNext();){
			IRow row=(IRow)iter.next();
			result.add(row.toList(cols));
		}
		return result;
	}

  public Object[][] toArray2(){
  	String[] columns=getColumns();
  	Object[][] result=new Object[size()][columns.length];
  	for(int i=0;i<rowList.size();i++) {
  		IRow row=rowList.get(i);
  		Object[] arr=row.toList().toArray();
  		result[i]=arr;
  	}
  	return result;
  }

	@Override
  public Object[][] toArray2(boolean isOutputColumn,String...cols ){
  	String[] columns=cols.length==0?getColumns():cols;
  	Object[][] result=new Object[size()+(isOutputColumn?1:0)][columns.length];
  	if(isOutputColumn)
  		result[0]=columns;
  	for(int i=isOutputColumn?1:0;i<rowList.size();i++) {
  		IRow row=rowList.get(i);
  		Object[] arr=row.toList().toArray();
  		result[i]=arr;
  	}
  	return result;
  }

	public List<List> toList2(){
		return toList2(true,getColumns());
	}

	@Override
	public List<List> toList2(boolean isOutputColumn,String...cols){
		List<List> result=new ArrayList<>();
		if(cols.length==0) cols=getColumns();
		if(isOutputColumn){
			result.add(Arrays.asList(cols));
		}
		for(int i=isOutputColumn?1:0;i<rowList.size();i++) {
			IRow row=rowList.get(i);
			result.add(row.toList(cols));
		}
		return result;
	}


	public String[][] toArray(boolean trim,String...cols) throws SQLException{
		if(cols.length==0)
			cols=this.columns;
		List rowList=gainAllRow();
		List<List> result=new ArrayList<List>(rowList.size()+1);
		result.add(Arrays.asList(cols));
		int size=rowList.size();
		for(int i=0;i<size;i++){
			IRow row=(IRow)rowList.get(i);
			ArrayList<String> list=new ArrayList(cols.length);
			Map map=row.record();
			for(int j=0;j<cols.length;j++){
				if(trim)
					list.add(EasyStr.getStringNoNull(map.get(cols[j])).trim());
				else
					list.add(EasyStr.getStringNoNull(map.get(cols[j])));
			}
			result.add(list);
		}
		return EasyStr.listToArr2(result);
	}

	public Iterator<T> iterator(){
		/*getRowSize();
		return (Iterator<T>)rowList.iterator();*/
		return new ResultsetIterator();
	}

	public Adder reduce(Function<T,?> fn) throws SQLException{
		Adder result=new CharAppender(',');
		for(first();next();){
			T row=(T)getCurrent();
			result.add(fn.apply(row));
		}
		return result;
	}

	public <Rtn extends Adder>Rtn reduce(Rtn result,Function<T,?> fn) throws SQLException{
		for(first();next();){
			T row=(T)getCurrent();
			result.add(fn.apply(row));
		}
		return result;
	}

	/**使用lambda计算数量*/
	public double reduceDbl(ToDoubleFunction<T> fn) throws SQLException{
		Double result=0D;
		for(first();next();){
			T row=(T)getCurrent();
			result+=fn.applyAsDouble(row);
		}
		return result;
	}

	/**使用lambda计算数量*/
  public int reduceInt(ToIntFunction<T> fn) throws SQLException{
		int result=0;
		for(first();next();){
			T row=(T)getCurrent();
			result+=fn.applyAsInt(row);
		}
		return result;
	}

	/**使用lambda计算数量*/
	public long reduceLong(ToLongFunction<T> fn) throws SQLException{
		long result=0;
		for(first();next();){
			T row=(T)getCurrent();
			result+=fn.applyAsLong(row);
		}
		return result;
	}

	/**使用lambda表达式过滤*/
  public Long[] getLongs(Function<T,Long> fn) {
  	Long[] result=new Long[size()];
  	int i=0;
  	for(T row:this){
			result[i++]=fn.apply(row);
		}
  	return result;
  }

	/**使用lambda表达式修改记录内容*/
	public ABResultSet<T> update(Consumer<T> fn) throws SQLException {
		for(first();next();){
			T row=(T)getCurrent();
			fn.accept(row);
		}
		return this;
	}


  public String[] getStrings(Function<T,String> fn) {
		size();
  	String[] result=new String[size()];
  	int i=0;
  	for(T row:this){
			result[i++]=fn.apply(row);
		}
  	return result;
  }

	/**得到某个字段的所有记录的内容*/
	@Override
	public String[] getStrings(String columnName){
		size();
		return RowSetUtils.getValues(rowList,columnName,String.class);
	}

	@Override
	public Integer[] getIntegers(String columnName){
		size();
		return RowSetUtils.getValues(rowList,columnName,Integer.class);
	}

	@Override
	public Object[] getObjects(String columnName){
		size();
		return RowSetUtils.getValues(rowList,columnName,Object.class);
	}

	@Override
	public Double[] getDoubles(String columnName){
		size();
		return RowSetUtils.getValues(rowList,columnName,Double.class);
	}

	public String[] getStrings(String columnName,boolean isDistinct) {
		size();
		return RowSetUtils.getValues(rowList,columnName,String.class,isDistinct);
	}
	public Integer[] getIntegers(String columnName,boolean isDistinct) {
		size();
		return RowSetUtils.getValues(rowList,columnName,Integer.class,isDistinct);
	}
	public Long[] getLongs(String columnName,boolean isDistinct) {
		size();
		return RowSetUtils.getValues(rowList,columnName,Long.class,isDistinct);
	}
	public Double[] getDoubles(String columnName,boolean isDistinct) {
		size();
		return RowSetUtils.getValues(rowList,columnName,Double.class,isDistinct);
	}
	public Number[] getNumbers(String columnName,boolean isDistinct) {
		size();
		return RowSetUtils.getValues(rowList,columnName,Number.class,isDistinct);
	}
	public Object[] getObjects(String columnName,boolean isDistinct) {
		size();
		return RowSetUtils.getValues(rowList,columnName,Object.class,isDistinct);
	}
	public BigDecimal[] getBigDecimals(String columnName,boolean isDistinct) {
		size();
		return RowSetUtils.getValues(rowList,columnName,BigDecimal.class,isDistinct);
	}
	public Date[] getDates(String columnName,boolean isDistinct) {
		return RowSetUtils.getValues(rowList,columnName,Date.class,isDistinct);
	}
	public LocalDate[] getLocalDates(String columnName,boolean isDistinct) {
		return RowSetUtils.getValues(rowList,columnName,LocalDate.class,isDistinct);
	}

	public LocalDateTime[] getLocalDateTimes(String columnName,boolean isDistinct) {
		return RowSetUtils.getValues(rowList,columnName,LocalDateTime.class,isDistinct);
	}
	public List getValues(String columnName,boolean isDistinct){
		size();
		return RowSetUtils.getValues(rowList,columnName,isDistinct);
	}
	public List getValues(String columnName){
		size();
		return RowSetUtils.getValues(rowList,columnName,true);
	}

	public String toString(String field,String delimiter){
		return esdk.array.toStr(getValues(field,true),delimiter+"");
	}

	@Override
	public EasyNumber sum(String...columns){
		EasyNumber result=new EasyNumber();
		for(int i=0,n=size();i<n;i++){
			IRow row=rowList.get(i);
			for(int j=0;j<columns.length;j++){
				Number num=(Number)(row).get(columns[j]);
				if(num!=null)
					result.add(num);
			}
		}
		return result;
	}

	public EasyNumber<Number> sum(Function<T,? extends Number> fn){
		EasyNumber result=new EasyNumber();
		for(T row:this){
			result.add(fn.apply(row));
		}
		return result;
	}

	@Override
	public ABResultSet sort(String...columnKeys){
		return sort(false,columnKeys);
	}

	@Override
	public ABResultSet sort(final boolean isDesc,final String...cols){
		if(size()>0){
			IRow currentRow=null;
			if(isRange(cursorPos))
				currentRow=(IRow)rowList.get(cursorPos);
			Collections.sort(this.rowList,new Comparator(){
				@Override
				public int compare(Object o1,Object o2){
					IRow i1=(IRow)o1;
					IRow i2=(IRow)o2;
					int result=0;
					for(int i=0;i<cols.length&&result==0;i++){
						if(isDesc){
							result=EasyObj.compareTo(i2.get(cols[i]),i1.get(cols[i]));
							if(result>0)
								break;
						}else{
							result=EasyObj.compareTo(i1.get(cols[i]),i2.get(cols[i]));
							if(result<0)
								break;
						}
					}
					return result;
				}
			});
			cursorPos=rowList.indexOf(currentRow);
		}
		return this;
	}

	public ABResultSet sort(final OrderBy...cols){
		size();
		IRow currentRow=null;
		if(isRange(cursorPos))
			currentRow=(IRow)rowList.get(cursorPos);
		Collections.sort(this.rowList,new Comparator(){
			@Override
			public int compare(Object o1,Object o2){
				IRow i1=(IRow)o1;
				IRow i2=(IRow)o2;
				int result=0;
				for(int i=0;i<cols.length&&result==0;i++){
					if(cols[i].isDescent())
						result=EasyObj.compareTo(i2.get(cols[i].getField().getName()),i1.get(cols[i].getField().getName()));
					else
						result=EasyObj.compareTo(i1.get(cols[i].getField().getName()),i2.get(cols[i].getField().getName()));
				}
				return result;
			}
		});
		cursorPos=rowList.indexOf(currentRow);
		return this;
	}

	public ABRowSet distinct(String...fields){
		return (ABRowSet)RowSetUtils.distinct(new ABRowSet(this),fields);
	}

	@Override
	protected Object clone() throws CloneNotSupportedException{
		ABResultSet result=new ABResultSet(this.rs);
		result.rowList=this.rowList;
		result.rsmd=this.rsmd;
		result.isCachedAllRow=this.isCachedAllRow;
		result.mapColumnClass=this.mapColumnClass;
		result.columns=this.columns;
		result._isClosed=this._isClosed;
		return result;
	}

	private class ResultsetIterator implements Iterator<T>{
		int cursor=-1;

		public boolean hasNext(){
			if(!isCachedAllRow && rowList.size()<=cursor+1)
				try{
					ABResultSet.this.next();
				}catch(SQLException e){
					throw new SQLRuntimeException(e);
				}
			return isRange(cursor+1);
		}

		public T next(){
			if(!isCachedAllRow&&rowList.size()==cursor+1){
				try{
					if(rs.next()){
						cursor++;
						if(cursor==rowList.size()){
							addRowList(getRow(cursor));
						}
					}else{
						isCachedAllRow=true;
						close();
						return (T)getRow(cursor);
					}
				}catch(Exception e){
					throw new SQLRuntimeException(e);
				}
			}else{
				if(cursor<rowList.size())
					cursor++;
			}
			return (T)getRow(cursor);
		}

		public void remove(){
			esdk.serr("暂不实现Remove功能");
		}
	}

	public void setSelect(ISelect select){
		this.select = select;
	}

	/**执行select.count返回总记录数*/
	public int totalCount(){
		if(totalCount>0)
			return totalCount;
		try{
			return select.count();
		}catch(SQLException e){
			throw new SQLRuntimeException(e);
		}
	}

	public void fillTotalCount(int totalCount){
		this.totalCount = totalCount;
	}

	public String getFirstString() throws SQLException{
		if(first()){
			String result=getCurrentRow().getString(getColumns()[0]);
			close();
			return result;
		}else
			return null;
	}

	public Integer getFirstInt() throws SQLException{
		if(first()){
			Integer result=getCurrentRow().getInteger(getColumns()[0]);
			close();
			return result;
		}else
			return null;
	}

	public Long getFirstLong() throws SQLException{
		if(first()){
			Long result=getCurrentRow().getLong(getColumns()[0]);
			close();
			return result;
		}else
			return null;
	}

	public Double getFirstDouble() throws SQLException{
		if(first()){
			Double result=getCurrentRow().getDouble(getColumns()[0]);
			close();
			return result;
		}else
			return null;
	}

	public LocalDateTime getFirstDate() throws SQLException{
		if(first()){
			LocalDateTime result=getCurrentRow().getLocalDateTime(getColumns()[0]);
			close();
			return result;
		}else
			return null;
	}

	public Boolean getFirstBoolean() throws SQLException{
		if(first()){
			Boolean result=getCurrentRow().getBoolean(getColumns()[0]);
			close();
			return result;
		}else
			return null;
	}

	public BigDecimal getFirstBigDecimal() throws SQLException{
		if(first()){
			BigDecimal result=getCurrentRow().getBigDecimal(getColumns()[0]);
			close();
			return result;
		}else
			return null;
	}

}
